// -----------------------------------------------------------------
// ClipPolygon.cpp
// Implementation file for class ClipPolygon, which does
// clipping on lines in a 2 dimensional plane.
//
// CS 4280  9:30 am
// Instructor: Mr. Rague
//
// Learning Team C
//     Members:
//     Jon Mann
//     Jared Pack
//     Joshua Clayton
// -----------------------------------------------------------------


// -----------------------------------------------------------------
//   Change Control Section
// -----------------------------------------------------------------
//       Team Member: Joshua Clayton 
//       Version: 1.0
//       Date:  01/15/10
//       Initial revision. Forked from cliprect.cpp, changed names 
//       of class and files
//
//       Team Member: Jon Mann
//       Version: 1.1
//       Date:  02/14/10
//       Added CyrusBeckClip function 
//       unable to test until chopCI is implemented	
//		 added norm() and dot() functions for vector calculations
//
//       Team Member: Joshua Clayton 
//       Version: 1.2
//       Date:  01/15/10
//       Changed clipping function to use internal list<Point2>
//
//
//       Team Member: Jared Pack
//       Version: 1.2
//       Date:  02/15/10
//       Added chopCI function for testing whether the ray is entering
//       or exiting the polygon.
//
//       Team Member: Jon Mann
//       Version: 1.3
//       Date:  02/15/10
//       Integrated CyrusBeckClip with Jared's chopCI 
//       fixed numer and denom calculation parameters
//
//       Team Member: Jon Mann
//       Version: 1.4
//       Date:  02/16/10
//       Added one more iteration to test closing line on polygon
//		 		
// -----------------------------------------------------------------

#ifdef _WIN32
#include<windows.h> // needed for windows systems
#endif


#ifdef DEBUG
#include <cstdio>
#endif



#include <math.h>
#include "canvas1.h"
#include "ClipPolygon.h"

ClipPolygon::ClipPolygon(void)
: ConvexPolygon()
{
}

ClipPolygon::ClipPolygon(list<Point2> &points)
: ConvexPolygon(points)
{
}

bool ClipPolygon::chopCI(double& tIn, double& tOut, double numer, double denom)
{
	double tHit;
	if (denom < 0) // ray is entering
	{
		tHit = numer / denom;
		if (tHit > tOut) return false; // early out
		else if (tHit > tIn) tIn = tHit; // take larger t
	}
	else if (denom > 0) // ray is exiting
	{
		tHit = numer / denom;
		if (tHit < tIn) return false; // early out
		if (tHit < tOut) tOut = tHit; // take smaller t
	}
	else // denom is 0, ray is parallel
	{
		if (numer <= 0) return false; // missed the line
	}
		return true; // CI is still non-empty
}

// tests our randomly generated line against each edge of our polygon
bool ClipPolygon::CyrusBeckClip(Point2 &first, Point2 &second)
{
	double numer, denom; // used to find the hit time for each line
	double tIn = 0.0, tOut = 1.0;
	Point2 c, tmp, lFirst, lSecond, tmpNorm, startPoint;

	// get the endpoints of our first line from the polygon
	startPoint = pointList.front();
	lSecond = pointList.front();

	// <form vector:c = seg.second - seg.first>
	c.set(second.getX() - first.getX(), second.getY() - first.getY());

	// iterate through our list of polygon edges, and chop at each bounding line
	for(list<Point2>::const_iterator it = pointList.begin(); it != pointList.end(); ++it) 
	{
		// get the endpoints of our next line from the polygon
		lFirst = lSecond;
		lSecond = *it;

		// preliminary set for our normal
		tmpNorm.set(lFirst.getX() - lSecond.getX(), lFirst.getY() - lSecond.getY());

//		cout << lSecond.getX() << endl;
//		cout << lSecond.getY() << endl;

		// <form vector tmp = L.line[i].pt - first>
		tmp.set(lSecond.getX() - first.getX(), lSecond.getY() - first.getY());
		
		numer = dot(norm(tmpNorm), tmp);
		denom = dot(norm(tmpNorm), c);

		if (!chopCI(tIn, tOut, numer, denom)) return false; // early out
	}

	// one more iteration to close the polygon
	lFirst = lSecond;
	lSecond = startPoint;

	// preliminary set for our normal
	tmpNorm.set(lFirst.getX() - lSecond.getX(), lFirst.getY() - lSecond.getY());

//	cout << lSecond.getX() << endl;
//	cout << lSecond.getY() << endl;

	// <form vector tmp = L.line[i].pt - first>
	tmp.set(lSecond.getX() - first.getX(), lSecond.getY() - first.getY());
	
	numer = dot(norm(tmpNorm), tmp);
	denom = dot(norm(tmpNorm), c);

	if (!chopCI(tIn, tOut, numer, denom)) return false; // early out

	// adjust the endpoints of the segment; do second one first
	if (tOut < 1.0) // second if the endpoint was altered
	{
		second.set(first.getX() + c.getX() * tOut, first.getY() + c.getY() * tOut);
//		cout << "second endpoint altered" << endl;
	}
	if (tIn > 0.0) // first endpoint was altered
	{
		first.set(first.getX() + c.getX() * tIn, first.getY() + c.getY() * tIn);
//		cout << "first endpoint altered" << endl;
	}

	return true; // some part of the segment survives
}


	
